home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 183_01 / comsup.c < prev    next >
Text File  |  1984-06-21  |  19KB  |  960 lines

  1. /*
  2.  
  3.  commsupp.c    - communications support for DeSmet C
  4.  
  5.  Tom Poindexter- March, 1984
  6.  
  7.  routines:
  8.  
  9.   init_com     - initialize comm port, interrupts, baud, data, parity, stop
  10.   uninit_com   - disable interrupts, flushes buffer
  11.   send_brk     - send break signal
  12.   set_xoff     - enable XON, XOFF protocol
  13.   recd_xoff    - return true if XOFF received
  14.   sent_xoff    - return true if XOFF sent
  15.   inp_cnt      - returns the number of unread bytes in receive buffer
  16.   inp_char     - return one byte from buffer
  17.   inp_strn     - transfer n bytes from buffer to string
  18.   outp_char    - send one byte
  19.   outp_strn    - send n bytes of a string, up to end of string
  20.   com_stat     - return line status (high byte) and modem status (low byte)
  21.   on_com       - specify a routine to execute when a byte is received
  22.  
  23.  internal routines:
  24.   -in commsupp.c-
  25.   port_chk     - validate the port number (C88)
  26.  
  27.   -in commasm.a-
  28.   int_c_handlr - interrupt driven port read, com1:, store in buffer (ASM88)
  29.   int_b_handlr - interrupt driven port read, com2:, store in buffer (ASM88)
  30.   sysint       - call a system routine (ASM88)
  31.   inb           - input byte from hardware port (ASM88)
  32.   outb           - output byte to hardware port (ASM88)
  33.   cli           - clear interrupts (ASM88)
  34.   sti           - set interrupts   (ASM88)
  35.  
  36.  standard DeSmet C library functions called:
  37.  
  38.   _lmove     - block move outside C data
  39.   _move      - block move within C data
  40.   _showcs    - get code segment
  41.   _showds    - get data segment
  42.   malloc     - allocate memory
  43.  
  44.  
  45. */
  46.  
  47. /* global parm data for two com ports */
  48.  
  49. struct
  50.  {
  51.   int  port_base;
  52.   char *buff_addr;
  53.   int  buff_len;
  54.   char *buff_head;
  55.   char *buff_tail;
  56.   int  buff_cnt;
  57.   int  x_state;
  58.   int  x_recd;
  59.   int  x_sent;
  60.   int  org_int_off;
  61.   int  org_int_seg;
  62.   int  (*on_com_rtn)();
  63.  }
  64.  _com_parms[2];
  65.  
  66.  
  67. /* global defines */
  68. #define FALSE      0
  69. #define TRUE      1
  70. #define ERROR      -1
  71.  
  72. /* defines for 8250 serial controller */
  73. #define DATAPORT  0
  74. #define INT_REG   1
  75. #define INT_ID      2
  76. #define LCTL_REG  3
  77. #define MDM_REG   4
  78. #define LCTL_STAT 5
  79. #define MDM_STAT  6
  80. #define LSB_BAUD  0
  81. #define MSB_BAUD  1
  82. #define DLAB      0x80
  83. #define DLAB_OFF  0x7f
  84. #define MDM_BRK   0x40
  85. #define PAR_NONE  0x00
  86. #define PAR_EVEN  0x18
  87. #define PAR_ODD   0x08
  88. #define PAR_STICK 0x20
  89. #define DATA_RDY  0x01
  90. #define OUT2_DR   0x0b
  91. #define BREAK_ON  0x40
  92. #define THRE      0x20
  93. /* count to wait for THRE */
  94. #define TIME      0xffff
  95.  
  96. /* defines for break request */
  97. #define TIME_OF_DAY 0x1a
  98. #define HALF_SEC  9
  99.  
  100. /* baud rate divisor constants */
  101. #define B110      1047
  102. #define B150      768
  103. #define B300      384
  104. #define B450      256
  105. #define B600      192
  106. #define B1200      96
  107. #define B2400      48
  108. #define B4800      24
  109. #define B9600      12
  110. /* defines to mask baud divisors MSB and LSB */
  111. #define MASK_LSB  0xff00
  112. #define MASK_MSB  0x00ff
  113.  
  114. /* defines for 8259 interrupt controller */
  115. #define C8259_1   0x21
  116. #define C8259_3   0x20
  117. #define ENBL_IRQ4 0xef
  118. #define DIS_IRQ4  0x10
  119. #define ENBL_IRQ3 0xf7
  120. #define DIS_IRQ3  0x08
  121. #define EOI_IRQ4  0x64
  122. #define EOI_IRQ3  0x63
  123. #define IRQ4_VEC  0x0c
  124. #define IRQ3_VEC  0x0b
  125.  
  126. /* defines for data areas */
  127. #define SYS_VEC   0x0
  128. #define ROM_DATA  0x40
  129. #define INT_DSEG  2
  130.  
  131.  
  132. /****************************************************************************/
  133.  
  134. /* init_com
  135.  
  136.       parms:
  137.         port: 1 = com1:, 2 = com2:
  138.         baud: 110, 150, 300, 450, 600, 1200, 2400, 4800, 9600
  139.       parity: 0 = none, 1 = odd, 2 = even, 3 = mark, 4 = space
  140.         data: 5, 6, 7, 8
  141.         stop: 1, 2
  142.     buff_len: length desired for receive buffer ( 0 < buff_len < 32767 )
  143.  
  144.    returns:
  145.       ERROR = com port not available or invalid parm value
  146.        TRUE = ok
  147.  
  148. */
  149.  
  150. init_com (port, baud, parity, data, stop, buff_len)
  151.  
  152. int port;
  153. int baud;
  154. int parity;
  155. int data;
  156. int stop;
  157. int buff_len;
  158.  
  159. {
  160.  
  161.   int divisor;
  162.   int buff_addr;
  163.   int line_reg;
  164.   int data_seg;
  165.   int code_seg;
  166.   int int_c_handlr();
  167.   int int_b_handlr();
  168.   int int_handlr_addr;
  169.  
  170.   /*  get C program segment registers */
  171.  
  172.   data_seg = _showds ();
  173.   code_seg = _showcs ();
  174.  
  175.   /* validate port; store port address */
  176.  
  177.   if (port < 1 || port > 2)
  178.     return (ERROR);
  179.   else
  180.    {
  181.     port--;
  182.     _lmove (2,port*2,ROM_DATA,&_com_parms[port].port_base,data_seg);
  183.     if (_com_parms[port].port_base == 0)
  184.       return (ERROR);
  185.    }
  186.  
  187.  
  188.   /* validate baud; set baud divisors */
  189.  
  190.   switch (baud)
  191.    {
  192.     case  110:
  193.       divisor =  B110;
  194.       break;
  195.     case  150:
  196.       divisor =  B150;
  197.       break;
  198.     case  300:
  199.       divisor =  B300;
  200.       break;
  201.     case  450:
  202.       divisor =  B450;
  203.       break;
  204.     case  600:
  205.       divisor =  B600;
  206.       break;
  207.     case 1200:
  208.       divisor = B1200;
  209.       break;
  210.     case 2400:
  211.       divisor = B2400;
  212.       break;
  213.     case 4800:
  214.       divisor = B4800;
  215.       break;
  216.     case 9600:
  217.       divisor = B9600;
  218.       break;
  219.     default:
  220.       return (ERROR);
  221.    }
  222.  
  223.  
  224.   /* validate parity; set line control register parity */
  225.  
  226.   switch (parity)
  227.    {
  228.      case 0:  /* none  */
  229.        line_reg = PAR_NONE;
  230.        break;
  231.      case 1:  /* odd   */
  232.        line_reg = PAR_ODD;
  233.        break;
  234.      case 2:  /* even  */
  235.        line_reg = PAR_EVEN;
  236.        break;
  237.      case 3:  /* mark  */
  238.        line_reg = PAR_ODD | PAR_STICK;
  239.        break;
  240.      case 4:  /* space */
  241.        line_reg = PAR_EVEN | PAR_STICK;
  242.        break;
  243.      default:
  244.        return (ERROR);
  245.     }
  246.  
  247.  
  248.   /* validate data len; set line control register data length */
  249.  
  250.   if (data < 5 || data > 8)
  251.     return (ERROR);
  252.   else
  253.     line_reg |= data - 5;
  254.  
  255.  
  256.   /* validate stop bits; set line control register stop bits */
  257.  
  258.   if (stop < 1 || stop > 2)
  259.     return (ERROR);
  260.   else
  261.     line_reg |=  (stop - 1) << 2;
  262.  
  263.  
  264.   /* validate buffer len; allocate memory, set initial settings */
  265.  
  266.   if (buff_len < 1 || buff_len > 32767)
  267.     return (ERROR);
  268.   else
  269.    {
  270.     _com_parms[port].buff_addr    = malloc (buff_len);
  271.     if (_com_parms[port].buff_addr == 0)
  272.       return (ERROR);
  273.     _com_parms[port].buff_len    = buff_len;
  274.     _com_parms[port].buff_head    = _com_parms[port].buff_addr;
  275.     _com_parms[port].buff_tail    = _com_parms[port].buff_addr;
  276.     _com_parms[port].buff_cnt    = 0;
  277.     _com_parms[port].x_state    = FALSE;
  278.     _com_parms[port].x_recd    = FALSE;
  279.     _com_parms[port].x_sent    = FALSE;
  280.     _com_parms[port].on_com_rtn = FALSE;
  281.    }
  282.  
  283.   /* set 8250 baud divisor */
  284.  
  285.   outb (_com_parms[port].port_base + LCTL_REG, DLAB);
  286.   outb (_com_parms[port].port_base + LSB_BAUD, divisor & MASK_MSB);
  287.   outb (_com_parms[port].port_base + MSB_BAUD, (divisor & MASK_LSB) >> 8);
  288.  
  289.  
  290.   /* set 8250 line control register */
  291.  
  292.   outb (_com_parms[port].port_base + LCTL_REG, line_reg);
  293.  
  294.  
  295.   /* set IRQx interrupt to point to interrupt handler ;
  296.      enable 8259 IRQx interrupts;
  297.      enable 8250 data ready interrupts;
  298.      enable 8250 OUT2 ,DTR, RTS */
  299.  
  300.   cli ();
  301.  
  302.   if (port == 0)
  303.    {
  304.     /* IRQ4, com1: */
  305.     _lmove (2,IRQ4_VEC*4,  SYS_VEC,&_com_parms[port].org_int_off,data_seg);
  306.     _lmove (2,IRQ4_VEC*4+2,SYS_VEC,&_com_parms[port].org_int_seg,data_seg);
  307.  
  308.     int_handlr_addr = (unsigned) &int_c_handlr;
  309.     _lmove (2,&int_handlr_addr,data_seg,IRQ4_VEC*4,  SYS_VEC);
  310.     _lmove (2,&code_seg,       data_seg,IRQ4_VEC*4+2,SYS_VEC);
  311.  
  312.     outb (C8259_1, (inb (C8259_1) & ENBL_IRQ4));
  313.  
  314.    }
  315.  
  316.   else
  317.    {
  318.     /* IRQ3, com2: */
  319.     _lmove (2,IRQ3_VEC*4,  SYS_VEC,&_com_parms[port].org_int_off,data_seg);
  320.     _lmove (2,IRQ3_VEC*4+2,SYS_VEC,&_com_parms[port].org_int_seg,data_seg);
  321.  
  322.     int_handlr_addr = (unsigned) &int_b_handlr;
  323.     _lmove (2,&int_handlr_addr,data_seg,IRQ3_VEC*4,  SYS_VEC);
  324.     _lmove (2,&code_seg,       data_seg,IRQ3_VEC*4+2,SYS_VEC);
  325.  
  326.     outb (C8259_1, (inb (C8259_1) & ENBL_IRQ3));
  327.  
  328.    }
  329.  
  330.   /* save C data segment in interrupt handlr routine */
  331.   int_handlr_addr = (unsigned) &int_c_handlr + INT_DSEG;
  332.   _lmove (2,&data_seg,data_seg,int_handlr_addr,code_seg);
  333.  
  334.  
  335.   outb (_com_parms[port].port_base + INT_REG, DATA_RDY);
  336.  
  337.   outb (_com_parms[port].port_base + MDM_REG, OUT2_DR);
  338.  
  339.   sti ();